package pay.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pay.commont.*;
import pay.dao.*;
import pay.entity.*;
import pay.service.MessageService;
import pay.service.PayService;
import pay.utils.AesUtil;
import pay.utils.DistributedLockUtil;
import pay.utils.VipUtils;

import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service("wechatPayService")
public class WechatPayServiceImpl implements PayService {

    @Autowired
    private AesUtil aesUtil;

    @Autowired
    DistributedLockUtil distributedLockUtil;

    @Autowired
    private RedissonClient redissonClient;

    @Resource
    private PayHistoryMapper payHistoryMapper;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private MessageService messageService;

    @Resource
    private CouponAppUserDao couponAppUserDao;

    @Resource
    OrderGoodMapper orderGoodMapper;

    @Resource
    private GoodMapper goodMapper;

    @Resource
    private ContestItemMapper contestItemMapper;

    @Resource
    private TeamMapper teamMapper;

    @Resource
    private TeamUserMapper teamUserMapper;

    @Resource
    private ContestItemUserMapper contestItemUserMapper;

    @Autowired
    VipUtils vipUtils;

    @Override
    @Transactional
    public void handleCallBack(Map<String, Object> data) {
        Map<RLock, Boolean> lockMap = new ConcurrentHashMap<>();
        RLock orderLock = null;
        RLock outTradeNoLock = null;
        boolean isLocked = false;
        boolean isOutTradeNoLocked = false;
        try {
            Map<String, String> resource = (Map<String, String>) data.get("resource");
            String associatedData = resource.get("associated_data");
            String nonce = resource.get("nonce");
            String ciphertext = resource.get("ciphertext");
            WxPayTransaction wxPayTransaction = aesUtil.decryptToWxPayTransaction(associatedData.getBytes(), nonce.getBytes(), ciphertext);
            if (wxPayTransaction == null) {
                throw new RuntimeException("未知错误");
            }
            if (!wxPayTransaction.getTradeState().equals("SUCCESS")) {
                throw new RuntimeException("订单未支付成功");
            }
            outTradeNoLock = redissonClient.getLock(LockType.OUT_TRADE_NO.getName() + wxPayTransaction.getOutTradeNo());
            isOutTradeNoLocked = outTradeNoLock.tryLock(5, 60, TimeUnit.SECONDS);
            if (!isOutTradeNoLocked) {
                throw new RuntimeException("加锁失败");
            }
            PayHistoryEntity payHistory = payHistoryMapper.selectOne(new QueryWrapper<PayHistoryEntity>().eq("pay_sn", wxPayTransaction.getOutTradeNo()));

            if (payHistory == null) {
                throw new RuntimeException("支付未存在");
            }
            if (payHistory.getStatus().equals(PayStatus.COMPLETE.getStatus())) {
                throw new RuntimeException("已支付的订单");
            }
            orderLock = redissonClient.getLock(LockType.ORDER.getName() + payHistory.getOrderId());
            isLocked = orderLock.tryLock(5, 60, TimeUnit.SECONDS);
            if (!isLocked) {
                throw new RuntimeException("加锁失败");
            }
            OrdersEntity ordersEntity = orderMapper.selectOne(new QueryWrapper<OrdersEntity>().eq("id", payHistory.getOrderId()));
            if (ordersEntity == null) {
                throw new RuntimeException("订单不存在");
            }
            // 更新pay_history
            OffsetDateTime odt = OffsetDateTime.parse(wxPayTransaction.getSuccessTime());
            Date from = Date.from(odt.toInstant());
            payHistory.setUpdateTime(from);
            payHistory.setOutTradeNo(wxPayTransaction.getTransactionId());
            payHistory.setAmount(BigDecimal.valueOf(wxPayTransaction.getAmount().getTotal()).divide(BigDecimal.valueOf(100)));
            payHistory.setStatus(PayStatus.COMPLETE.getStatus());

            int status = payHistoryMapper.updateById(payHistory);
            if (status <= 0) {
                throw new RuntimeException("服务器异常");
            }
            // 更新order
            ordersEntity.setPayTime(from);
            ordersEntity.setStatus(OrderStatus.PAY_SUCCESS.getCode());
            status = orderMapper.updateById(ordersEntity);
            if (status <= 0) {
                throw new RuntimeException("服务器异常");
            }
            updateVip(ordersEntity);
            // 修改优惠券状态
            if (ordersEntity.getCouponAppUserId() != null) {
                RLock couponLock = redissonClient.getLock(LockType.COUPON.getName() + ordersEntity.getCouponAppUserId());
                boolean isCouponLocked = couponLock.tryLock(5, 60, TimeUnit.SECONDS);
                lockMap.put(couponLock, isCouponLocked);
                if (!isCouponLocked) {
                    throw new RuntimeException("优惠券加锁失败");
                }
                CouponAppUserEntity couponAppUserEntity = couponAppUserDao.selectOne(new QueryWrapper<CouponAppUserEntity>().eq("id", ordersEntity.getCouponAppUserId()));
                if (couponAppUserEntity != null) {
                    couponAppUserEntity.setStatus(CouponStatus.USE.getStatus());
                    status = couponAppUserDao.updateById(couponAppUserEntity);
                    if (status <= 0) {
                        throw new RuntimeException("服务器异常");
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            if (isLocked) {
                orderLock.unlock();
            }
            if (isOutTradeNoLocked) {
                outTradeNoLock.unlock();
            }
            lockMap.forEach((rLock, lock) -> {
                if (lock) {
                    rLock.unlock();
                }
            });
        }
    }




    @Transactional
    public void updateVip(OrdersEntity order) {
        Map<RLock, Boolean> lockMap = new ConcurrentHashMap<>();
        try {
            List<OrderGoodsEntity> orderGoodList = orderGoodMapper.selectList(new QueryWrapper<OrderGoodsEntity>().eq("order_id", order.getId()));
            try {
                messageService.paySuccessSendMessage(order);
            } catch (Exception e) {
                e.printStackTrace();
            }
            for (OrderGoodsEntity orderGoods : orderGoodList) {
                if (order.getOrderType().equals(OrdersType.POST.getCode())) {
                    if (order.getPostOrderGoodsId() != null & !order.getPostOrderGoodsId().isEmpty()) {
                        List<Integer> postOrderGoodsIdList = Arrays.stream(order.getPostOrderGoodsId().split(",")).map(String::trim).map(Integer::valueOf).collect(Collectors.toList());
                        List<OrderGoodsEntity> orderGoodsEntityList = orderGoodMapper.selectList(new QueryWrapper<OrderGoodsEntity>().in("id", postOrderGoodsIdList));
                        for (OrderGoodsEntity orderGoodsEntity : orderGoodsEntityList) {
                            orderGoodsEntity.setIsVerification(OrderGoodVerificationStatus.POST.getCode());
                            orderGoodMapper.updateById(orderGoodsEntity);
                        }
                    }
                }
                GoodsEntity good = goodMapper.selectOne(new QueryWrapper<GoodsEntity>().eq("id", orderGoods.getGoodsId()));
                RLock lock = redissonClient.getLock(LockType.GOODS.getName() + good.getId());
                boolean isLocked = lock.tryLock(5, 60, TimeUnit.SECONDS);
                lockMap.put(lock, isLocked);
                if (!isLocked) {
                    throw new RuntimeException("商品加锁失败");
                }
                if (good.getGoodsType().equals(GoodsType.VIP.getType())) {
                    vipUtils.activateMember(order.getUserId(), order.getUserId(), good.getDays(), VipOpenType.CHARGE.getCode(), order.getId());
                }
                if (good.getGoodsType().equals(GoodsType.GAME.getType())) {
                    good.setSaled(good.getSaled() + 1);
                } else {
                    good.setSaled(good.getSaled() + orderGoods.getCount());
                }
                int status = goodMapper.updateById(good);
                if (status <= 0) {
                    throw new RuntimeException("服务器异常");
                }
                // 如果订单为团队赛
                if (good.getGoodsType().equals(GoodsType.GAME.getType())) {
                    ContestItemEntity contestItem = contestItemMapper.selectOne(new QueryWrapper<ContestItemEntity>().eq("id", good.getRelateProjectId()));
                    if (contestItem.getGameType().equals(GameType.TEAM.getCode())) {
                        // 创建子订单，并绑定到现有orders上
                        OrdersEntity ordersEntity = new OrdersEntity();
                        ordersEntity.setOrderSn(order.getOrderSn());
                        ordersEntity.setCreateTime(order.getCreateTime());
                        ordersEntity.setAutoCancelTime(order.getAutoCancelTime());
                        ordersEntity.setPayTime(order.getPayTime());
                        ordersEntity.setStatus(order.getStatus());
                        ordersEntity.setTotalPrice(order.getTotalPrice());
                        ordersEntity.setCouponPrice(order.getCouponPrice());
                        ordersEntity.setPayAmount(order.getPayAmount());
                        ordersEntity.setPayType(order.getPayType());
                        ordersEntity.setChannelFee(order.getChannelFee());
                        ordersEntity.setActualReceivedAmount(order.getActualReceivedAmount());
                        ordersEntity.setIsMain(OrderMainType.Sub.getCode());
                        // 查找所有团队成员预约单
                        TeamEntity teamEntity = teamMapper.selectOne(new QueryWrapper<TeamEntity>().eq("contest_item_id", good.getRelateProjectId()).eq("user_id", order.getUserId()));

                        List<TeamUserEntity> teamUserList = teamUserMapper.selectList(new QueryWrapper<TeamUserEntity>().eq("team_id", teamEntity.getId()));

                        for (TeamUserEntity teamUser : teamUserList) {
                            if (teamUser.getTeamNo() != 0) {
                                // 不为队长,创建子订单
                                ContestItemUserEntity contestItemUser = contestItemUserMapper.selectOne(new QueryWrapper<ContestItemUserEntity>().eq("id", teamUser.getContestItemUserId()));
                                if (contestItemUser != null) {
                                    ordersEntity.setReservationId(contestItemUser.getId());
                                    ordersEntity.setUserId(contestItemUser.getUserId());
                                    status = orderMapper.insert(ordersEntity);
                                    if (status <= 0) {
                                        throw new RuntimeException("服务器异常");
                                    }
                                    List<OrderGoodsEntity> orderGoodsEntityList = orderGoodMapper.selectList(new QueryWrapper<OrderGoodsEntity>().eq("order_id", order.getId()));
                                    for (OrderGoodsEntity orderGoodsEntity : orderGoodsEntityList) {
                                        orderGoodsEntity.setOrderId(ordersEntity.getId());
                                        status = orderGoodMapper.insert(orderGoodsEntity);
                                        if (status <= 0) {
                                            throw new RuntimeException("服务器异常");
                                        }
                                    }
                                    try {
                                        messageService.paySuccessSendMessage(ordersEntity);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            lockMap.forEach((rLock, lock) -> {
                if (lock) {
                    rLock.unlock();
                }
            });
        }
    }
}
